package com.yuanxin.baidumap;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.location.LocationManager;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.util.Log;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MyLocationConfiguration;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.TextureMapView;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.model.LatLngBounds;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.Permission;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import static com.yuanxin.baidumap.ReactMapLocationModule.defaultOption;

/**
 * Created by yiyang on 16/2/29.
 */
public class ReactMapView {

    private static final String TAG = "ReactMapView";

    private TextureMapView mMapView;

    private LocationClient mLocationClient;

    private ReactMapMyLocationConfiguration mConfiguration;

    private Activity mActivity;

    private boolean autoZoomToSpan = true;

    public boolean isAutoZoomToSpan() {
        return autoZoomToSpan;
    }

    public void setAutoZoomToSpan(boolean autoZoomToSpan) {
        this.autoZoomToSpan = autoZoomToSpan;
    }

    private List<ReactMapMarker> mMarkers = new ArrayList<ReactMapMarker>();
    private List<String> mMarkerIds = new ArrayList<String>();

    private List<ReactMapOverlay> mOverlays = new ArrayList<ReactMapOverlay>();
    private List<String> mOverlayIds = new ArrayList<String>();

    private int zoomLevel;

    public void setZoomLevel(int zoomLevel) {
        this.zoomLevel = zoomLevel;
    }

    private BaiduMapViewManager baiduMapViewManager;

    public ReactMapView(BaiduMapViewManager baiduMapViewManager, TextureMapView mapView, Activity mActivity) {
        this.mMapView = mapView;
        this.baiduMapViewManager = baiduMapViewManager;
        this.mActivity = mActivity;
    }

    public TextureMapView getView() {
        return this.mMapView;
    }

    public BaiduMap getMap() {
        return this.mMapView.getMap();
    }

    public void setOverlays(List<ReactMapOverlay> overlays) {
        List<String> newOverlayIds = new ArrayList<String>();
        List<ReactMapOverlay> overlaysToDelete = new ArrayList<ReactMapOverlay>();
        List<ReactMapOverlay> overlaysToAdd = new ArrayList<ReactMapOverlay>();

        for (ReactMapOverlay overlay :
                overlays) {
            if (overlay instanceof ReactMapOverlay == false) {
                continue;
            }

            newOverlayIds.add(overlay.getId());

            if (!mOverlayIds.contains(overlay.getId())) {
                overlaysToAdd.add(overlay);
            }
        }

        for (ReactMapOverlay overlay :
                this.mOverlays) {
            if (overlay instanceof ReactMapOverlay == false) {
                continue;
            }

            if (!newOverlayIds.contains(overlay.getId())) {
                overlaysToDelete.add(overlay);
            }
        }

        if (!overlaysToDelete.isEmpty()) {
            for (ReactMapOverlay overlay :
                    overlaysToDelete) {
                overlay.getPolyline().remove();
                this.mOverlays.remove(overlay);
            }
        }

        if (!overlaysToAdd.isEmpty()) {
            for (ReactMapOverlay overlay :
                    overlaysToAdd) {
                if (overlay.getOptions() != null) {
                    overlay.addToMap(this.getMap());
                    this.mOverlays.add(overlay);
                }
            }
        }

        this.mOverlayIds = newOverlayIds;

    }


    public List<ReactMapMarker> getmMarkers() {
        return mMarkers;
    }

    public void setMarker(List<ReactMapMarker> markers) {

        List<String> newMarkerIds = new ArrayList<String>();
        List<ReactMapMarker> markersToDelete = new ArrayList<ReactMapMarker>();
        List<ReactMapMarker> markersToAdd = new ArrayList<ReactMapMarker>();

        for (ReactMapMarker marker :
                markers) {
            if (marker instanceof ReactMapMarker == false) {
                continue;
            }

            newMarkerIds.add(marker.getId());

            if (!mMarkerIds.contains(marker.getId())) {
                markersToAdd.add(marker);
            }
        }

        for (ReactMapMarker marker :
                this.mMarkers) {
            if (marker instanceof ReactMapMarker == false) {
                continue;
            }

            if (!newMarkerIds.contains(marker.getId())) {
                markersToDelete.add(marker);
            }
        }

        if (!markersToDelete.isEmpty()) {
            for (ReactMapMarker marker :
                    markersToDelete) {
                marker.getMarker().remove();
                this.mMarkers.remove(marker);
            }
        }

        if (!markersToAdd.isEmpty()) {
            for (ReactMapMarker marker :
                    markersToAdd) {
                if (marker.getOptions() != null) {
                    marker.addToMap(this.getMap());
                    this.mMarkers.add(marker);
                }
            }
        }

        this.mMarkerIds = newMarkerIds;
    }


    public void onMapLoaded() {
        if (this.autoZoomToSpan) {
            this.zoomToSpan();
        }
    }

    public void zoomToSpan(List<ReactMapMarker> markers, List<ReactMapOverlay> overlays) {
        LatLngBounds.Builder builder = new LatLngBounds.Builder();
        boolean hasBuilded = false;
        if (markers != null && markers.size() > 0) {
            for (ReactMapMarker marker :
                    markers) {
                if (marker != null && marker.getOptions() != null) {
                    LatLng location = marker.getOptions().getPosition();
                    builder.include(location);
                    hasBuilded = true;
                }
            }
        }
        if (overlays != null && overlays.size() > 0) {
            for (ReactMapOverlay overlay :
                    overlays) {
                if (overlay != null && overlay.getOptions() != null) {
                    for (LatLng location :
                            overlay.getOptions().getPoints()) {
                        builder.include(location);
                        hasBuilded = true;
                    }
                }
            }
        }
        if (hasBuilded) {
            this.getMap().animateMapStatus(MapStatusUpdateFactory.newLatLngBounds(builder.build()));
        }
    }

    private boolean isFirst = false;

    public void zoomToSpan() {
        this.zoomToSpan(this.mMarkers, this.mOverlays);
    }

    BDAbstractLocationListener listener = new BDAbstractLocationListener() {
        @Override
        public void onReceiveLocation(BDLocation bdLocation) {
           // Log.d("local", "info : " +mLocationClient.getVersion()+" | " +(bdLocation.getFloor()!=null)+" | "+ bdLocation.getLocTypeDescription());
           // Log.d("local", "result : " +bdLocation.getLocType()+" | "+bdLocation.getNetworkLocationType()+" | "+ bdLocation.getLatitude() + " | " + bdLocation.getLongitude() + " | " + bdLocation.getSatelliteNumber() + " | "
//                    + bdLocation.getAddrStr()+"\n");
            if (getMap().isMyLocationEnabled()) {
                float radius = 0;
                if (ReactMapMyLocationConfiguration.isShowAccuracyCircle()) {
                    radius = bdLocation.getRadius();
                }
                MyLocationData locData = new MyLocationData.Builder()
                        .accuracy(radius)
                        .latitude(bdLocation.getLatitude())
                        .longitude(bdLocation.getLongitude())
                        .build();
                getMap().setMyLocationData(locData);
                if (!isFirst) {
                    isFirst = true;
                    LatLng latLng = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
                    MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(latLng, zoomLevel);
                    getMap().setMapStatus(mapStatusUpdate);
                    baiduMapViewManager.onChange(ReactMapView.this, bdLocation.getLatitude(), bdLocation.getLongitude());
                }
                if (mLocationClient != null && mLocationClient.isStarted()) {
                    baiduMapViewManager.onDidChangeUserLocation(ReactMapView.this, bdLocation);
//                                mLocationClient.stop();
                }
            }
        }
    };

    private void getUserLocation(boolean showsUserLocation) {
        if (getMap() == null) {
            return;
        }
        if (showsUserLocation != getMap().isMyLocationEnabled()) {
            getMap().setMyLocationEnabled(showsUserLocation);
            if (showsUserLocation && mLocationClient == null) {
                mLocationClient = new LocationClient(mMapView.getContext());
                mLocationClient.setLocOption(defaultOption());
                mLocationClient.registerLocationListener(listener);
                mLocationClient.start();
            } else if (showsUserLocation) {
                if (mLocationClient.isStarted()) {
                    mLocationClient.requestLocation();
                } else {
                    mLocationClient.start();
                }
            } else if (mLocationClient != null) {
                if (mLocationClient.isStarted()) {
                    mLocationClient.stop();
                }
            }

        }
        if (showsUserLocation) {
            startLocationServer();
        }else{
            stopLocationServer();
        }
    }

    /**
     * 停止定位服务
     */
    public void stopLocationServer() {
        if (mLocationClient != null) {
            if (mLocationClient.isStarted()) {
                mLocationClient.unRegisterLocationListener(listener);
                mLocationClient.stop();
            }
        }
    }

    /**
     * 启动定位服务
     */
    public void startLocationServer() {
        if (mLocationClient == null) {
            mLocationClient = new LocationClient(mActivity);
        }
        mLocationClient.registerLocationListener(listener);
        mLocationClient.setLocOption(defaultOption());
        if (mLocationClient.isStarted()) {
            mLocationClient.requestLocation();
        } else {
            mLocationClient.start();
        }
    }




    public void setShowsUserLocation(final boolean showsUserLocation) {
        AndPermission.with(mActivity)
                .permission(Permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
                .onGranted(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {
                        try {
                            getUserLocation(showsUserLocation);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                })
                .onDenied(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {
                        for (int i = 0; i < permissions.size(); i++) {
                           // Log.e("MapView", "拒绝了权限：" + permissions.get(i));
                        }
                    }
                }).start();
    }


    public void setConfiguration(ReactMapMyLocationConfiguration configuration) {
        this.mConfiguration = configuration;
        this.mConfiguration.setConfigurationUpdateListener(new ReactMapMyLocationConfiguration.ConfigurationUpdateListener() {
            @Override
            public void onConfigurationUpdate(ReactMapMyLocationConfiguration aConfiguration) {
                if (getMap() != null) {
                    getMap().setMyLocationConfiguration(aConfiguration.getConfiguration());
                }
            }
        });
        if (getMap() != null) {
            getMap().setMyLocationConfiguration(configuration.getConfiguration());
        }
    }

}
